use std::sync::Arc;
use std::{vec, result};

use tonic::{Request, Response, Status};
use crate::gen::entities::{Order, MetaData};
use crate::gen::mini_mulazim::{CreateOrderRequest, GetOrdersOfRiderRequest, GetOrdersOfUserRequest, GetOrdersOfUserResponse, Id, KeysRequest, KeysResponse, OrderDeliveryRequest};
use crate::gen::mini_mulazim::order_service_server::OrderService;

use super::data_container::DataContainer;
use super::exts::{IntoTonicResponse, ToOption, OptionToResult, Apply, ToKeysResponse, GetEntityKey};
use super::structs::GenericEntityIndex;

/**
 * @author Dream-Lab مۇختەرجان مەخمۇت
 * @email ug-project@outlook.com
 * @create date 2022-07-25 01:22:00
 * @modify date 2022-07-25 01:22:00
 * @desc [description]
*/

pub struct OrderServiceImpl {
    pub data: Arc<DataContainer>
}

#[async_trait::async_trait]
impl OrderService for OrderServiceImpl {
    async fn create(&self, request: Request<CreateOrderRequest>) -> Result<Response<Order>, Status> {
        let request = request.into_inner();
        self.data.get_user_by_id(&request.user_id).into_result(Status::not_found("User not found"))?;
        self.data.get_restaurant_by_id(&request.restaurant_id).into_result(Status::not_found("Restaurant not found"))?;
        {
            let order = self.data.insert_order(Order{
                user: None,
                user_id: request.user_id.clone(),
                restaurant: None,
                restaurant_id: request.restaurant_id,
                foods: request.foods_id,
                rider: None,
                rider_id: "".into(),
                meta: MetaData::new_with_default_value().into(),
                completed: false,
            });
            ///Generate index for UserOrder
            self.data.insert_data(&self.data.orders_of_user, self.data.get_data_by_id_of(&self.data.orders_of_user, &request.user_id.clone()).apply(|index|{
                if let None = index {
                    *index = Some(GenericEntityIndex {
                        key: request.user_id.clone(),
                        value: vec![],
                    })
                }
            }).unwrap().apply(|index|{
                index.value.push(order.key());
            }));
            order
        }.into_option().into_tonic_response()
    }

    async fn update(&self, request: Request<Order>) -> Result<Response<Order>, Status> {
        self.data.update_order(request.into_inner()).into_option().into_tonic_response()
    }

    async fn get_by_id(&self, request: Request<Id>) -> Result<Response<Order>, Status> {
        self.data.get_order_by_id(&request.into_inner().uuid).apply(|me|{
            if let Some(ref mut me) = me {
                me.user = self.data.get_user_by_id(&me.user_id);
                me.rider = self.data.get_rider_by_id(&me.rider_id);
                me.restaurant = self.data.get_restaurant_by_id(&me.restaurant_id);
            }
        }).into_tonic_response()
    }

    async fn list(&self, request: Request<KeysRequest>) -> Result<Response<KeysResponse>, Status> {
        self.data.get_keys_of(&self.data.orders, &request.into_inner()).into_keys_response().into_option().into_tonic_response()
    }

    async fn get_orders_of_user(&self, request: Request<GetOrdersOfUserRequest>) -> Result<Response<GetOrdersOfUserResponse>, Status> {
        let request = request.into_inner();
        self.data.get_user_by_id(&request.user_id).into_result(Status::not_found("User not found"))?;
        let orders = {
            let order_guard = self.data.orders.lock().expect("Cannot acquire the lock");
            let index_guard = self.data.orders_of_user.lock().expect("Cannot acquire the lock");
            Vec::from_iter(index_guard.get(&request.user_id).expect("Program has a bug if you can see me").value.iter().map(|order_key|order_guard.get(order_key)).filter(|order| order.is_some()).map(|order| order.unwrap().clone()))
        };
        GetOrdersOfUserResponse {
            orders
        }.into_option().into_tonic_response()
    }

    async fn get_orders_of_rider(&self, request: Request<GetOrdersOfRiderRequest>) -> Result<Response<GetOrdersOfUserResponse>, Status> {
        self.data.get_rider_by_id(&request.get_ref().rider_id).into_result(Status::not_found("Rider not found."))?;
        let orders = {
            let order_guard = self.data.orders.lock().expect("Cannot acquire the lock");
            let index_guard = self.data.orders_of_rider.lock().expect("Cannot acquire the lock");
            Vec::from_iter(index_guard.get(&request.get_ref().rider_id).expect("Program has a bug if you can see me").value.iter().map(|order_key|order_guard.get(order_key)).filter(|order| order.is_some()).map(|order| order.unwrap().clone()))
        };
        GetOrdersOfUserResponse {
            orders
        }.into_option().into_tonic_response()
    }

    async fn delivery(&self, request: Request<OrderDeliveryRequest>) -> Result<Response<Order>, Status> {
        self.data.get_rider_by_id(&request.get_ref().rider_id).into_result(Status::not_found("Rider not found."))?;
        let order = self.data.get_order_by_id(&request.get_ref().order_id);
        if let None = order {
            return None.into_tonic_response();
        }
        let mut order = order.unwrap();
        order.rider_id = request.get_ref().rider_id.clone();
        self.data.update_order(order).into_option().into_tonic_response()
    }
}
